#ifndef __ENGINE_CHANNEL_included
#define __ENGINE_CHANNEL_included

#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/asio.hpp>
#include "RequestSetup.h"
#include "../engine/Device.h"

using namespace boost::asio;
using namespace boost::asio::ip;

#define CHANNEL_BUFFER_SIZE 1024

namespace Engine {

class CSession;
class CDevice;

class CChannelBuffer {

	char mBuffer[CHANNEL_BUFFER_SIZE];
	int mTailPos;

public :

	CChannelBuffer() : mTailPos(0) { }

	void Reset() { mTailPos = 0; }
	void Move(int n) { mTailPos += n; }

	char* GetWritePointer(int& size) {
		size = CHANNEL_BUFFER_SIZE - mTailPos;
		return &mBuffer[mTailPos];
	}

	char* GetReadPointer(int& size) {
		size = mTailPos;
		return &mBuffer[0];
	}
};

class CChannel : public boost::enable_shared_from_this<CChannel> {

	int mId;
	boost::shared_ptr<tcp::socket> mSocket[2];
	boost::shared_ptr<CRequestSetup> mPendingSetup;
	CChannelBuffer mBuffers[2];
	boost::weak_ptr<CSession> mSession;
	//void HandleWrite(int sid, const boost::system::error_code& error);
	//void HandleRead(int sid, const boost::system::error_code& error, size_t bytes_transferred);

public :

	CChannel() : mId(0) { }
	virtual ~CChannel() { 
		DebugStream << "Channel deleted : " << mId << '\n';
	}

	void SetId(int id) { mId = id; }
	int GetId() { return mId; }

	CChannelBuffer& GetBuffer(int idx) { return mBuffers[idx]; }

	bool HasBuild() { return mSocket[1] != NULL; }
	void PendingSetup(boost::shared_ptr<CRequestSetup> r) { 
		mPendingSetup = r; 
	}
	void CancelPendingSetup() {
		mPendingSetup.reset();
	}

	void SetSession(boost::shared_ptr<CSession> session) { mSession = boost::weak_ptr<CSession>(session); }
	void ResetSession() { mSession.reset(); }

	void SetSocket(int idx, boost::shared_ptr<tcp::socket> s) { mSocket[idx] = s; }
	void ResetSocket(int idx) { mSocket[idx].reset(); }
	tcp::socket& GetSocket(int idx) { return *(mSocket[idx]); }
	boost::shared_ptr<tcp::socket> GetSocketPtr(int idx) { return mSocket[idx]; }

	boost::shared_ptr<CRequestSetup> GetPendingSetupRequest() { return mPendingSetup; }

	void ScheduleRead(int sid);
	void Start() {
		ScheduleRead(0);
		ScheduleRead(1);
	}

	bool Connect(Engine::DeviceRef dev);
	void Close();
};

typedef boost::shared_ptr<CChannel> ChannelRef;

}

#endif //__ENGINE_CHANNEL_included